/*
 * Copyright (c) 2022 Libre Solar Technologies GmbH
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <zephyr/device.h>

#include <zephyr/drivers/uart.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/drivers/gpio.h>

#include <string.h>

#include <nrfx.h>
#include <drivers/include/nrfx_rramc.h>
#include <hal/nrf_glitchdet.h>

/* change this to any other UART peripheral if desired */
#define UART_DEVICE_NODE DT_CHOSEN(zephyr_shell_uart)

#define MSG_SIZE 32

#define SPI_FLASH_TEST_REGION_OFFSET 0xf000
#define SPI_FLASH_SECTOR_SIZE        4096

#if DT_HAS_COMPAT_STATUS_OKAY(jedec_spi_nor)
#define SPI_FLASH_COMPAT jedec_spi_nor
#elif DT_HAS_COMPAT_STATUS_OKAY(jedec_mspi_nor)
#define SPI_FLASH_COMPAT jedec_mspi_nor
#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_qspi_nor)
#define SPI_FLASH_COMPAT st_stm32_qspi_nor
#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_ospi_nor)
#define SPI_FLASH_COMPAT st_stm32_ospi_nor
#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_xspi_nor)
#define SPI_FLASH_COMPAT st_stm32_xspi_nor
#elif DT_HAS_COMPAT_STATUS_OKAY(nordic_qspi_nor)
#define SPI_FLASH_COMPAT nordic_qspi_nor
#else
#define SPI_FLASH_COMPAT invalid
#endif

/* queue to store up to 10 messages (aligned to 4-byte boundary) */
K_MSGQ_DEFINE(uart_msgq, MSG_SIZE, 10, 4);

static const struct device *const uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE);

/* receive buffer used in UART ISR callback */
static char rx_buf[MSG_SIZE];
static int rx_buf_pos;
static int lc=-1;
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
/*
 * Read characters from UART until line end is detected. Afterwards push the
 * data to the message queue.
 */
void serial_cb(const struct device *dev, void *user_data)
{
	uint8_t c;

	if (!uart_irq_update(uart_dev)) {
		return;
	}
	if (!uart_irq_rx_ready(uart_dev)) {
		return;
	}
	/* read until FIFO empty */
	// CLS + INS + LC + data
	while (uart_fifo_read(uart_dev, &c, 1) == 1) {
		rx_buf[rx_buf_pos++] = c;
		/* else: characters beyond buffer size are dropped */
		if(rx_buf_pos == 5)
			lc = rx_buf[4];
		if(lc>=0 && rx_buf_pos > lc+4)
		{
			rx_buf[rx_buf_pos] = '\0';
			k_msgq_put(&uart_msgq, &rx_buf, K_NO_WAIT);
			lc=-1;
			rx_buf_pos=0;
		}
	}
}

/*
 * Print a null-terminated string character by character to the UART interface
 */
void print_uart(char *buf)
{
	int msg_len = strlen(buf);

	for (int i = 0; i < msg_len; i++) {
		uart_poll_out(uart_dev, buf[i]);
	}
}

void print_uart_lc(char *buf,uint8_t lc)
{
	for (int i = 0; i < lc; i++) {
		uart_poll_out(uart_dev, buf[i]);
	}
}


int hexchar_to_int(char c) {
    if ('0' <= c && c <= '9') return c - '0';
    if ('A' <= c && c <= 'F') return c - 'A' + 10;
    if ('a' <= c && c <= 'f') return c - 'a' + 10;
    return -1; // 非法字符
}

// 输入：hex 字符串（长度必须为偶数）
// 输出：填入 bytes 中（长度不超过 max_len）
// 返回值：成功转换的字节数；负数表示出错
int hexstr_to_bytes(const char *hexstr, uint8_t *bytes, size_t max_len) {
    size_t len = strlen(hexstr);
    if (len % 2 != 0) return -1; // 字符串必须是偶数长度

    size_t byte_len = len / 2;
    if (byte_len > max_len) return -2; // 输出缓冲区不够

    for (size_t i = 0; i < byte_len; i++) {
        int hi = hexchar_to_int(hexstr[2 * i]);
        int lo = hexchar_to_int(hexstr[2 * i + 1]);
        if (hi < 0 || lo < 0) return -3; // 非法字符
        bytes[i] = (uint8_t)((hi << 4) | lo);
    }

    return (int)byte_len;
}

#define RRAM_BASE 0x00154000

int main(void)
{
	char tx_buf[MSG_SIZE];
	uint8_t buffer[64]={0};
	uint8_t buffer1[64]={0};
	uint8_t CLA,INS,P1,P2,LC;
	uint32_t* ptr;
	int rc;
	if (!device_is_ready(uart_dev)) {
		printk("UART device not found!");
		return 0;
	}
	const struct device *flash_dev = DEVICE_DT_GET_ONE(SPI_FLASH_COMPAT);

	/* configure interrupt and callback to receive data */
	int ret = uart_irq_callback_user_data_set(uart_dev, serial_cb, NULL);
	gpio_pin_configure_dt(&led0, GPIO_OUTPUT_INACTIVE);
	if (ret < 0) {
		if (ret == -ENOTSUP) {
			printk("Interrupt-driven UART API support not enabled\n");
		} else if (ret == -ENOSYS) {
			printk("UART device does not support interrupt-driven API\n");
		} else {
			printk("Error setting UART callback: %d\n", ret);
		}
		return 0;
	}
	uart_irq_rx_enable(uart_dev);

	/* indefinitely wait for input from the user */
	while (k_msgq_get(&uart_msgq, &tx_buf, K_FOREVER) == 0) {
		CLA = tx_buf[0];
		INS = tx_buf[1];
		P1  = tx_buf[2];
		P2  = tx_buf[3];
		LC  = tx_buf[4];
		switch(INS){
			case 0x01:
				memset(buffer,0xa5,64);
				gpio_pin_set_dt(&led0, 1);
				nrfx_rramc_buffer_read(buffer, 0x000ff080, 16);
				nrfx_rramc_buffer_read(buffer+16, 0x000ff280, 16);
				nrfx_rramc_buffer_read(buffer+32, 0x000ff480, 16);
				nrfx_rramc_buffer_read(buffer+48, 0x000ff680, 16);
				gpio_pin_set_dt(&led0, 0);
				volatile uint32_t *rramc_reg = (volatile uint32_t *)(0x5004b420);
				print_uart_lc((uint8_t *)rramc_reg,4);
				print_uart_lc(buffer,64);
				memset(buffer,0x5a,64);
				break;
			case 0x02:
				NRF_GLITCHDET_Type *xx;
				xx = (NRF_GLITCHDET_Type *)(0x5004b000);
				nrf_glitchdet_enable_set(xx,0);
				const char *test_data = "0123456789abcdef0000ffffffff000000000000ffffffff5a5a5a5a33cc33cc";
				uint8_t data[32];
				int len = hexstr_to_bytes(test_data, data, sizeof(data));
				nrfx_rramc_bytes_write(0x000ff080,data, 32);
				nrfx_rramc_bytes_write(0x000ff280,data+16, 32);
				nrfx_rramc_bytes_write(0x000ff480,data, 32);
				nrfx_rramc_bytes_write(0x000ff680,data+16, 32);
				nrfx_rramc_buffer_read(buffer, 0x000ff080, 32);
				print_uart_lc(buffer,32);
				break;
			case 0x03:
				*(volatile uint32_t *)(0xe0082404) = 0x0;
				gpio_pin_set_dt(&led0, 1);
				nrfx_rramc_buffer_read(buffer, 0x000ff080, 16);
				nrfx_rramc_buffer_read(buffer+16, 0x000ff280, 16);
				nrfx_rramc_buffer_read(buffer+32, 0x000ff480, 16);
				nrfx_rramc_buffer_read(buffer+48, 0x000ff680, 16);
				nrfx_rramc_buffer_read(buffer, 0x000ff880, 16);
				nrfx_rramc_buffer_read(buffer+16, 0x000ffa80, 16);
				nrfx_rramc_buffer_read(buffer+32, 0x000ffc80, 16);
				nrfx_rramc_buffer_read(buffer+48, 0x000ffe80, 16);
				gpio_pin_set_dt(&led0, 0);
				break;
			case 0x4:
				*(volatile uint32_t *)(0xe0082404) = 0x1;
				gpio_pin_set_dt(&led0, 1);
				nrfx_rramc_buffer_read(buffer, 0x000ff080, 16);
				nrfx_rramc_buffer_read(buffer+16, 0x000ff280, 16);
				nrfx_rramc_buffer_read(buffer+32, 0x000ff480, 16);
				nrfx_rramc_buffer_read(buffer+48, 0x000ff680, 16);
				nrfx_rramc_buffer_read(buffer, 0x000ff880, 16);
				nrfx_rramc_buffer_read(buffer+16, 0x000ffa80, 16);
				nrfx_rramc_buffer_read(buffer+32, 0x000ffc80, 16);
				nrfx_rramc_buffer_read(buffer+48, 0x000ffe80, 16);
				gpio_pin_set_dt(&led0, 0);
				break;
			default:
			print_uart("CLA ERROR.");
		}
		k_sleep(K_MSEC(10));
		rx_buf_pos=0;
	}
	return 0;
}
